/*  This file is part of o.O.

    o.O is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    o.O is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with o.O.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2013 Oliver Katz */

#include "builder.h"

using namespace std;

namespace oO
{
	pair<unsigned int, AST> Only::check(vector<Token> t, Page p)
	{
		pair<unsigned int, AST> rtn;
		rtn.first = 0;

		for (string::iterator i = t[0].get().begin(); i != t[0].get().end(); i++)
		{
			if (match.find(*i) == string::npos)
				return rtn;
		}

		rtn.first = 1;
		rtn.second["value"] = t[0];
		return rtn;
	}

	pair<unsigned int, AST> Any::check(vector<Token> t, Page p)
	{
		pair<unsigned int, AST> rtn;
		rtn.first = 1;
		rtn.second["value"] = t[0];
		return rtn;
	}

	Builder &Builder::operator << (Parser *p)
	{
		parsers[p->getName()] = p;
		return *this;
	}

	Parser *Builder::operator [] (std::string n)
	{
		return parsers[n];
	}

	void Builder::enableAllDebugging()
	{
		for (map<string, Parser *>::iterator i = parsers.begin(); i != parsers.end(); i++)
			i->second->enableDebugging();
	}
	
	void Builder::disableAllStrict()
	{
		for (map<string, Parser *>::iterator i = parsers.begin(); i != parsers.end(); i++)
			i->second->disableStrict();
	}

	Branch Builder::createAnyBranch()
	{
		vector<Parser*> tmp;
		for (map<string, Parser*>::iterator i = parsers.begin(); i != parsers.end(); i++)
			tmp.push_back(i->second);
		return Branch("*", tmp);
	}

	Leaf Builder::createLeaf(string n, string s)
	{
		Leaf rtn = Leaf(n, s);
		parsers[n] = new Leaf(rtn);
		return rtn;
	}

	Only Builder::createOnly(string n, string s)
	{
		Only rtn = Only(n, s);
		parsers[n] = new Only(rtn);
		return rtn;
	}

	Any Builder::createAny()
	{
		return Any();
	}

	Sequence Builder::createSequence(string n, vector<pair<string, string> > s)
	{
		Sequence rtn = Sequence(n);
		for (vector<pair<string, string> >::iterator i = s.begin(); i != s.end(); i++)
		{
			if (i->first.empty())
			{
				rtn.appendChild(parsers[i->second]);
			}
			else
			{
				if (i->second.compare("*") == 0)
					rtn.appendLabeled(i->first, new Any());
				else
					rtn.appendLabeled(i->first, parsers[i->second]);
			}
		}
		parsers[n] = new Sequence(rtn);
		return rtn;
	}

	Many Builder::createMany(string n, string s)
	{
		Many rtn = Many(n, parsers[s]);
		parsers[n] = new Many(rtn);
		return rtn;
	}

	Branch Builder::createBranch(string n, vector<string> s)
	{
		Branch rtn = Branch(n);
		for (vector<string>::iterator i = s.begin(); i != s.end(); i++)
			rtn << parsers[*i];
		parsers[n] = new Branch(rtn);
		return rtn;
	}

	Builder &Builder::create(Page p)
	{
		Tokenizer tokenizer = Tokenizer(" \n", "\"", "= : ;");
		vector<Token> tokens = tokenizer.tokenize(p.buffer());

		Leaf leafPrefix = Leaf("leaf-prefix", "leaf");
		Leaf onlyPrefix = Leaf("only-prefix", "only");
		Leaf anyPrefix = Leaf("any-prefix", "any");
		Leaf sequencePrefix = Leaf("sequence-prefix", "sequence");
		Leaf manyPrefix = Leaf("many-prefix", "many");
		Leaf branchPrefix = Leaf("branch-prefix", "branch");
		Leaf equals = Leaf("equals", "=");
		Leaf separator = Leaf("separator", ":");
		Leaf eol = Leaf("eol", ";");
		Only symbol = Only("symbol", "abcdefghijklmnopqrstuvwxyz-*");
		Any any = Any();

		Sequence leafSequence = Sequence("leaf");
		leafSequence.appendLabeled("prefix", &leafPrefix);
		leafSequence.appendLabeled("name", &symbol);
		leafSequence.appendLabeled("equals", &equals);
		leafSequence.appendLabeled("value", &any);

		Sequence onlySequence = Sequence("only");
		onlySequence.appendLabeled("prefix", &onlyPrefix);
		onlySequence.appendLabeled("name", &symbol);
		onlySequence.appendLabeled("equals", &equals);
		onlySequence.appendLabeled("value", &any);

		Sequence anySequence = Sequence("any");
		anySequence.appendLabeled("prefix", &anyPrefix);
		anySequence.appendLabeled("name", &symbol);

		Sequence sequenceSequence = Sequence("sequence");
		sequenceSequence.appendLabeled("prefix", &sequencePrefix);
		sequenceSequence.appendLabeled("name", &symbol);
		sequenceSequence.appendLabeled("equals", &equals);
		Sequence sequenceArgumentLabeled = Sequence("sequence-argument-labeled");
		sequenceArgumentLabeled.appendLabeled("name", &symbol);
		sequenceArgumentLabeled.appendLabeled("separator", &separator);
		sequenceArgumentLabeled.appendLabeled("value", &symbol);
		Sequence sequenceArgumentChild = Sequence("sequence-argument-child");
		sequenceArgumentChild.appendLabeled("value", &symbol);
		Branch sequenceArgument = Branch("sequence-argument");
		sequenceArgument << &sequenceArgumentLabeled;
		sequenceArgument << &sequenceArgumentChild;
		Many sequenceArguments = Many("sequence-arguments", &sequenceArgument);
		sequenceSequence.appendChild(&sequenceArguments);

		Sequence manySequence = Sequence("many");
		manySequence.appendLabeled("prefix", &manyPrefix);
		manySequence.appendLabeled("name", &symbol);
		manySequence.appendLabeled("equals", &equals);
		manySequence.appendLabeled("value", &symbol);

		Sequence branchSequence = Sequence("branch");
		branchSequence.appendLabeled("prefix", &branchPrefix);
		branchSequence.appendLabeled("name", &symbol);
		branchSequence.appendLabeled("equals", &equals);
		Sequence branchArgument = Sequence("branch-argument");
		branchArgument.appendLabeled("value", &symbol);
		Many branchArguments = Many("branch-arguments", &branchArgument);
		branchSequence.appendChild(&branchArguments);

		Branch lineBranch = Branch("line-branch");
		lineBranch << &leafSequence;
		lineBranch << &onlySequence;
		lineBranch << &anySequence;
		lineBranch << &sequenceSequence;
		lineBranch << &manySequence;
		lineBranch << &branchSequence;

		Sequence line = Sequence("line");
		line.appendChild(&lineBranch);
		line.appendLabeled("eol", &eol);

		Many lines = Many("lines", &line);
		pair<unsigned int, AST> res = lines.check(tokens, p);
		if (res.first == 0)
		{
			cerr << "error: failed to parser parser generation script\n";
			for (vector<Error>::iterator i = errorBuffer.begin(); i != errorBuffer.end(); i++)
				i->dump();
			errorBuffer.clear();
		}
		else
		{
			for (int k = 0; k < 2; k++)
			{
				for (AST::iterator i = res.second.begin(); i != res.second.end(); i++)
				{
					string type = i->begin()->getName();
					AST tmp = *(i->begin());
					if (type.compare("leaf") == 0)
					{
						createLeaf(tmp["name"].get(), tmp["value"].get());
					}
					else if (type.compare("only") == 0)
					{
						createOnly(tmp["name"].get(), tmp["value"].get());
					}
					else if (type.compare("sequence") == 0)
					{
						vector<pair<string, string> > vtmp;
						for (AST::iterator j = tmp.begin()->begin(); j != tmp.begin()->end(); j++)
						{
							pair<string, string> etmp;
							if (j->getName().compare("sequence-argument-labeled") == 0)
							{
								etmp.first = (*j)["name"].get();
								etmp.second = (*j)["value"].get();
							}
							else
							{
								etmp.first = "";
								etmp.second = (*j)["value"].get();
							}
							vtmp.push_back(etmp);
						}
						createSequence(tmp["name"].get(), vtmp);
					}
					else if (type.compare("many") == 0)
					{
						createMany(tmp["name"].get(), tmp["value"].get());
					}
					else if (type.compare("branch") == 0)
					{
						vector<string> vtmp;
						for (AST::iterator j = tmp.begin()->begin(); j != tmp.begin()->end(); j++)
						{
							vtmp.push_back((*j)["value"].get());
						}
						createBranch(tmp["name"].get(), vtmp);
					}
				}
			}
		}

		return *this;
	}
}

